using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
namespace Game1
{
    public class Camera
    {
        /// <summary>
        /// First person camera component for the demos, rotated by mouse.
        /// </summary>
        /// 
            protected Vector3 position;
            protected float speed;
            protected Matrix orientation;

            private Matrix view;
            private Matrix projection;
    
            public Vector3 angles = Vector3.Zero;

            private int widthOver2;
            private int heightOver2;

            private float fieldOfView = Microsoft.Xna.Framework.MathHelper.PiOver4;
            private float aspectRatio;
            private float nearPlaneDistance = 0.1f;
            private float farPlaneDistance = 10000.0f;

            private MouseState prevMouseState = new MouseState();

            private String cameraName;
            private bool Enabled = true;

            private Vector3 target = Vector3.Zero;

            public Vector3 Target { set { target = value; } }
        /*    public Vector3 Angles {
            get { return angles; }
            set { angles = value; } }*/

            /// <summary>
            /// Initializes new camera component.
            /// </summary>
            /// <param name="game">Game to which attach this camera.</param>
            public Camera(String cameraName)
            {
                position = new Vector3(0, 0, 0);
                
                
                aspectRatio = (float)Base.Window.ClientBounds.Width / (float)Base.Window.ClientBounds.Height;
                this.cameraName = cameraName;
                UpdateProjection();
            }

            /// <summary>
            /// Gets or sets camera position.
            /// </summary>
            public Vector3 getPosition() { return position; }
            public void setPosition(Vector3 position) { this.position = position; }
   
            public String Name { get{ return cameraName;} set { cameraName = value;} }

            /// <summary>
            /// Gets camera view matrix.
            /// </summary>
            public Matrix View {
                set { view = value; }
                get { return view; } }
            /// <summary>
            /// Gets or sets camera projection matrix.
            /// </summary>
            public Matrix Projection { get { return projection; } set { projection = value; } }
            /// <summary>
            /// Gets camera view matrix multiplied by projection matrix.
            /// </summary>
            public Matrix ViewProjection { get { return view * projection; } }

            /// <summary>
            /// Gets or sets camera field of view.
            /// </summary>
            public float FieldOfView { get { return fieldOfView; } set { fieldOfView = value; UpdateProjection(); } }
            /// <summary>
            /// Gets or sets camera aspect ratio.
            /// </summary>
            public float AspectRatio { get { return aspectRatio; } set { aspectRatio = value; UpdateProjection(); } }
            /// <summary>
            /// Gets or sets camera near plane distance.
            /// </summary>
            public float NearPlaneDistance { get { return nearPlaneDistance; } set { nearPlaneDistance = value; UpdateProjection(); } }
            /// <summary>
            /// Gets or sets camera far plane distance.
            /// </summary>
            public float FarPlaneDistance { get { return farPlaneDistance; } set { farPlaneDistance = value; UpdateProjection(); } }

            /// <summary>
            /// Gets or sets camera's target.
            /// </summary>
            public Vector3 ComplexTarget
            {
                get
                {
                    Matrix cameraRotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y);
                    return position + Vector3.Transform(Vector3.Forward, cameraRotation);
                }
                set
                {
                    Vector3 forward = Vector3.Normalize(position - value);
                    Vector3 right = Vector3.Normalize(Vector3.Cross(forward, Vector3.Up));
                    Vector3 up = Vector3.Normalize(Vector3.Cross(right, forward));

                    Matrix test = Matrix.Identity;
                    test.Forward = forward;
                    test.Right = right;
                    test.Up = up;
                    angles.X = -(float)Math.Asin(test.M32);
                    angles.Y = -(float)Math.Asin(test.M13);
                }
            }

            /// <summary>
            /// Updates camera with input and updates view matrix.
            /// </summary>
            /// <param name="gameTime"></param>
            public void Update(GameTime gameTime, Matrix cameraRotation)
            {
                if (Enabled)
                {
                    double elapsedTime = (double)gameTime.ElapsedGameTime.Ticks / (double)TimeSpan.TicksPerSecond;
                    ProcessInput((float)elapsedTime * 50.0f);
                    UpdateView(cameraRotation);

                    
                }
            }

            private void ProcessInput(float amountOfMovement)
            {
                Vector3 moveVector = new Vector3();
              
                KeyboardState keys = Keyboard.GetState();
                if (Input.IsKeyDown(Keys.NumPad6))
                    moveVector.X += amountOfMovement;
                if (Input.IsKeyDown(Keys.NumPad4))
                    moveVector.X -= amountOfMovement;
                if (Input.IsKeyDown(Keys.NumPad5))
                    moveVector.Z += amountOfMovement;
                if (Input.IsKeyDown(Keys.NumPad8))
                    moveVector.Z -= amountOfMovement;

                Matrix cameraRotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y);
                position += Vector3.Transform(moveVector, cameraRotation);

                MouseState currentMouseState = Mouse.GetState();

                if (currentMouseState.RightButton == ButtonState.Pressed && prevMouseState.RightButton == ButtonState.Released)
                {
                    Mouse.SetPosition(widthOver2, heightOver2);
                }
                else if (currentMouseState.RightButton == ButtonState.Pressed)
                {
                    if (currentMouseState.X != widthOver2)
                        angles.Y -= amountOfMovement / 80.0f * (currentMouseState.X - widthOver2);
                    if (currentMouseState.Y != heightOver2)
                        angles.X -= amountOfMovement / 80.0f * (currentMouseState.Y - heightOver2);

                    if (angles.X > 1.4) angles.X = 1.4f;
                    if (angles.X < -1.4) angles.X = -1.4f;
                    if (angles.Y > Math.PI) angles.Y -= 2 * (float)Math.PI;
                    if (angles.Y < -Math.PI) angles.Y += 2 * (float)Math.PI;

                    Mouse.SetPosition(widthOver2, heightOver2);
                }

                prevMouseState = currentMouseState;
            }

            private void UpdateProjection()
            {
                projection = Matrix.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlaneDistance, farPlaneDistance);
            }

            private void UpdateView(Matrix cameraRotation)
            {
                //Matrix cameraRotation = Matrix.CreateRotationX(angles.X) * Matrix.CreateRotationY(angles.Y) * Matrix.CreateRotationZ(angles.Z);                
                Vector3 targetPos = position + Vector3.Transform(Vector3.Forward, cameraRotation);
                Vector3 upVector = Vector3.Transform(Vector3.Up, cameraRotation);                
                view = Matrix.CreateLookAt(position, target, upVector);
            }

            public void Draw(GameTime gameTime,Camera camera)
            {
            }
        }
    }

